// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/gles2_cmd_decoder.h"

#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "gpu/command_buffer/common/gles2_cmd_format.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/cmd_buffer_engine.h"
#include "gpu/command_buffer/service/context_group.h"
#include "gpu/command_buffer/service/context_state.h"
#include "gpu/command_buffer/service/gl_surface_mock.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h"

#include "gpu/command_buffer/service/image_manager.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/mocks.h"
#include "gpu/command_buffer/service/program_manager.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "gpu/config/gpu_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_mock.h"
#include "ui/gl/gl_surface_stub.h"

#if !defined(GL_DEPTH24_STENCIL8)
#define GL_DEPTH24_STENCIL8 0x88F0
#endif

using ::gfx::MockGLInterface;
using ::testing::_;
using ::testing::DoAll;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::MatcherCast;
using ::testing::Mock;
using ::testing::Pointee;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::SetArgumentPointee;
using ::testing::SetArrayArgument;
using ::testing::StrEq;
using ::testing::StrictMock;

namespace gpu {
namespace gles2 {

    using namespace cmds;

    class GLES2DecoderGeometryInstancingTest : public GLES2DecoderWithShaderTest {
    public:
        GLES2DecoderGeometryInstancingTest()
            : GLES2DecoderWithShaderTest()
        {
        }

        void SetUp() override
        {
            InitState init;
            init.extensions = "GL_ANGLE_instanced_arrays";
            // Most of the tests in this file assume they're running on
            // desktop OpenGL, and large portions of the tests will become
            // no-ops if they aren't.
            init.gl_version = "opengl 2.1";
            init.has_alpha = true;
            init.has_depth = true;
            init.request_alpha = true;
            init.request_depth = true;
            init.bind_generates_resource = true;
            InitDecoder(init);
            SetupDefaultProgram();
        }
    };

    INSTANTIATE_TEST_CASE_P(Service,
        GLES2DecoderGeometryInstancingTest,
        ::testing::Bool());

    void GLES2DecoderManualInitTest::DirtyStateMaskTest(GLuint color_bits,
        bool depth_mask,
        GLuint front_stencil_mask,
        GLuint back_stencil_mask)
    {
        ColorMask color_mask_cmd;
        color_mask_cmd.Init((color_bits & 0x1000) != 0,
            (color_bits & 0x0100) != 0,
            (color_bits & 0x0010) != 0,
            (color_bits & 0x0001) != 0);
        EXPECT_EQ(error::kNoError, ExecuteCmd(color_mask_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        DepthMask depth_mask_cmd;
        depth_mask_cmd.Init(depth_mask);
        EXPECT_EQ(error::kNoError, ExecuteCmd(depth_mask_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        StencilMaskSeparate front_stencil_mask_cmd;
        front_stencil_mask_cmd.Init(GL_FRONT, front_stencil_mask);
        EXPECT_EQ(error::kNoError, ExecuteCmd(front_stencil_mask_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        StencilMaskSeparate back_stencil_mask_cmd;
        back_stencil_mask_cmd.Init(GL_BACK, back_stencil_mask);
        EXPECT_EQ(error::kNoError, ExecuteCmd(back_stencil_mask_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupExpectationsForApplyingDirtyState(
            false, // Framebuffer is RGB
            true, // Framebuffer has depth
            true, // Framebuffer has stencil
            color_bits, // color bits
            depth_mask, // depth mask
            false, // depth enabled
            front_stencil_mask, // front stencil mask
            back_stencil_mask, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Test that with an RGB backbuffer if we set the color mask to 1,1,1,1 it is
    // set to 1,1,1,0 at Draw time but is 1,1,1,1 at query time.
    TEST_P(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMask)
    {
        ColorMask cmd;
        cmd.Init(true, true, true, true);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, GetError())
            .WillOnce(Return(GL_NO_ERROR))
            .WillOnce(Return(GL_NO_ERROR))
            .RetiresOnSaturation();
        typedef GetIntegerv::Result Result;
        Result* result = static_cast<Result*>(shared_memory_address_);
        EXPECT_CALL(*gl_, GetIntegerv(GL_COLOR_WRITEMASK, result->GetData()))
            .Times(0);
        result->size = 0;
        GetIntegerv cmd2;
        cmd2.Init(GL_COLOR_WRITEMASK, shared_memory_id_, shared_memory_offset_);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
        EXPECT_EQ(
            decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_COLOR_WRITEMASK),
            result->GetNumResults());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
        EXPECT_EQ(1, result->GetData()[0]);
        EXPECT_EQ(1, result->GetData()[1]);
        EXPECT_EQ(1, result->GetData()[2]);
        EXPECT_EQ(1, result->GetData()[3]);
    }

    // Test that with no depth if we set DepthMask true that it's set to false at
    // draw time but querying it returns true.
    TEST_P(GLES2DecoderRGBBackbufferTest, RGBBackbufferDepthMask)
    {
        EXPECT_CALL(*gl_, DepthMask(true)).Times(0).RetiresOnSaturation();
        DepthMask cmd;
        cmd.Init(true);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, GetError())
            .WillOnce(Return(GL_NO_ERROR))
            .WillOnce(Return(GL_NO_ERROR))
            .RetiresOnSaturation();
        typedef GetIntegerv::Result Result;
        Result* result = static_cast<Result*>(shared_memory_address_);
        EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_WRITEMASK, result->GetData()))
            .Times(0);
        result->size = 0;
        GetIntegerv cmd2;
        cmd2.Init(GL_DEPTH_WRITEMASK, shared_memory_id_, shared_memory_offset_);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
        EXPECT_EQ(
            decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_WRITEMASK),
            result->GetNumResults());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
        EXPECT_EQ(1, result->GetData()[0]);
    }

    // Test that with no stencil if we set the stencil mask it's still set to 0 at
    // draw time but gets our value if we query.
    TEST_P(GLES2DecoderRGBBackbufferTest, RGBBackbufferStencilMask)
    {
        const GLint kMask = 123;
        EXPECT_CALL(*gl_, StencilMask(kMask)).Times(0).RetiresOnSaturation();
        StencilMask cmd;
        cmd.Init(kMask);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, GetError())
            .WillOnce(Return(GL_NO_ERROR))
            .WillOnce(Return(GL_NO_ERROR))
            .RetiresOnSaturation();
        typedef GetIntegerv::Result Result;
        Result* result = static_cast<Result*>(shared_memory_address_);
        EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_WRITEMASK, result->GetData()))
            .Times(0);
        result->size = 0;
        GetIntegerv cmd2;
        cmd2.Init(GL_STENCIL_WRITEMASK, shared_memory_id_, shared_memory_offset_);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
        EXPECT_EQ(
            decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_WRITEMASK),
            result->GetNumResults());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
        EXPECT_EQ(kMask, result->GetData()[0]);
    }

    // Test that if an FBO is bound we get the correct masks.
    TEST_P(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMaskFBO)
    {
        ColorMask cmd;
        cmd.Init(true, true, true, true);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupTexture();
        SetupVertexBuffer();
        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        DoEnableVertexAttribArray(2);
        DoVertexAttribPointer(2, 2, GL_FLOAT, 0, 0);
        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Check that no extra calls are made on the next draw.
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Setup Frame buffer.
        // needs to be 1x1 or else it's not renderable.
        const GLsizei kWidth = 1;
        const GLsizei kHeight = 1;
        const GLenum kFormat = GL_RGB;
        // Use a different texture for framebuffer to avoid drawing feedback loops.
        EXPECT_CALL(*gl_, GenTextures(_, _))
            .WillOnce(SetArgumentPointee<1>(kNewServiceId))
            .RetiresOnSaturation();
        GenHelper<cmds::GenTexturesImmediate>(kNewClientId);
        DoBindTexture(GL_TEXTURE_2D, kNewClientId, kNewServiceId);
        // Pass some data so the texture will be marked as cleared.
        DoTexImage2D(GL_TEXTURE_2D,
            0,
            kFormat,
            kWidth,
            kHeight,
            0,
            kFormat,
            GL_UNSIGNED_BYTE,
            kSharedMemoryId,
            kSharedMemoryOffset);
        DoBindFramebuffer(
            GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
        DoFramebufferTexture2D(GL_FRAMEBUFFER,
            GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D,
            kNewClientId,
            kNewServiceId,
            0,
            GL_NO_ERROR);
        DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
        EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
            .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
            .RetiresOnSaturation();

        // This time state needs to be set.
        SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Check that no extra calls are made on the next draw.
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Unbind
        DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0);

        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderManualInitTest, DepthEnableWithDepth)
    {
        InitState init;
        init.has_depth = true;
        init.request_depth = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        Enable cmd;
        cmd.Init(GL_DEPTH_TEST);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupDefaultProgram();
        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            true, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            true, // depth mask
            true, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, GetError())
            .WillOnce(Return(GL_NO_ERROR))
            .WillOnce(Return(GL_NO_ERROR))
            .RetiresOnSaturation();
        typedef GetIntegerv::Result Result;
        Result* result = static_cast<Result*>(shared_memory_address_);
        EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_TEST, _))
            .Times(0)
            .RetiresOnSaturation();
        result->size = 0;
        GetIntegerv cmd2;
        cmd2.Init(GL_DEPTH_TEST, shared_memory_id_, shared_memory_offset_);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
        EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_TEST),
            result->GetNumResults());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
        EXPECT_EQ(1, result->GetData()[0]);
    }

    TEST_P(GLES2DecoderManualInitTest, DepthEnableWithoutRequestedDepth)
    {
        InitState init;
        init.has_depth = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        Enable cmd;
        cmd.Init(GL_DEPTH_TEST);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupDefaultProgram();
        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, GetError())
            .WillOnce(Return(GL_NO_ERROR))
            .WillOnce(Return(GL_NO_ERROR))
            .RetiresOnSaturation();
        typedef GetIntegerv::Result Result;
        Result* result = static_cast<Result*>(shared_memory_address_);
        EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_TEST, _))
            .Times(0)
            .RetiresOnSaturation();
        result->size = 0;
        GetIntegerv cmd2;
        cmd2.Init(GL_DEPTH_TEST, shared_memory_id_, shared_memory_offset_);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
        EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_TEST),
            result->GetNumResults());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
        EXPECT_EQ(1, result->GetData()[0]);
    }

    TEST_P(GLES2DecoderManualInitTest, StencilEnableWithStencil)
    {
        InitState init;
        init.has_stencil = true;
        init.request_stencil = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        Enable cmd;
        cmd.Init(GL_STENCIL_TEST);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupDefaultProgram();
        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(
            true, // Framebuffer is RGB
            false, // Framebuffer has depth
            true, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            GLES2Decoder::kDefaultStencilMask, // front stencil mask
            GLES2Decoder::kDefaultStencilMask, // back stencil mask
            true); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, GetError())
            .WillOnce(Return(GL_NO_ERROR))
            .WillOnce(Return(GL_NO_ERROR))
            .RetiresOnSaturation();
        typedef GetIntegerv::Result Result;
        Result* result = static_cast<Result*>(shared_memory_address_);
        EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_TEST, _))
            .Times(0)
            .RetiresOnSaturation();
        result->size = 0;
        GetIntegerv cmd2;
        cmd2.Init(GL_STENCIL_TEST, shared_memory_id_, shared_memory_offset_);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
        EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_TEST),
            result->GetNumResults());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
        EXPECT_EQ(1, result->GetData()[0]);
    }

    TEST_P(GLES2DecoderManualInitTest, StencilEnableWithoutRequestedStencil)
    {
        InitState init;
        init.has_stencil = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        Enable cmd;
        cmd.Init(GL_STENCIL_TEST);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        SetupDefaultProgram();
        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(true, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1110, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays draw_cmd;
        draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, GetError())
            .WillOnce(Return(GL_NO_ERROR))
            .WillOnce(Return(GL_NO_ERROR))
            .RetiresOnSaturation();
        typedef GetIntegerv::Result Result;
        Result* result = static_cast<Result*>(shared_memory_address_);
        EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_TEST, _))
            .Times(0)
            .RetiresOnSaturation();
        result->size = 0;
        GetIntegerv cmd2;
        cmd2.Init(GL_STENCIL_TEST, shared_memory_id_, shared_memory_offset_);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
        EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_TEST),
            result->GetNumResults());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
        EXPECT_EQ(1, result->GetData()[0]);
    }

    TEST_P(GLES2DecoderManualInitTest, CachedColorMask)
    {
        InitState init;
        init.has_alpha = true;
        init.has_depth = true;
        init.has_stencil = true;
        init.request_alpha = true;
        init.request_depth = true;
        init.request_stencil = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        SetupDefaultProgram();
        SetupAllNeededVertexBuffers();
        SetupTexture();

        // Test all color_bits combinations twice.
        for (int i = 0; i < 32; i++) {
            GLuint color_bits = (i & 1 ? 0x0001 : 0x0000) | (i & 2 ? 0x0010 : 0x0000) | (i & 4 ? 0x0100 : 0x0000) | (i & 8 ? 0x1000 : 0x0000);

            // Toggle depth_test to force ApplyDirtyState each time.
            DirtyStateMaskTest(color_bits, false, 0xffffffff, 0xffffffff);
            DirtyStateMaskTest(color_bits, true, 0xffffffff, 0xffffffff);
            DirtyStateMaskTest(color_bits, false, 0xffffffff, 0xffffffff);
        }
    }

    TEST_P(GLES2DecoderManualInitTest, CachedDepthMask)
    {
        InitState init;
        init.has_alpha = true;
        init.has_depth = true;
        init.has_stencil = true;
        init.request_alpha = true;
        init.request_depth = true;
        init.request_stencil = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        SetupDefaultProgram();
        SetupAllNeededVertexBuffers();
        SetupTexture();

        // Test all depth_mask combinations twice.
        for (int i = 0; i < 4; i++) {
            bool depth_mask = (i & 1) == 1;

            // Toggle color masks to force ApplyDirtyState each time.
            DirtyStateMaskTest(0x1010, depth_mask, 0xffffffff, 0xffffffff);
            DirtyStateMaskTest(0x0101, depth_mask, 0xffffffff, 0xffffffff);
            DirtyStateMaskTest(0x1010, depth_mask, 0xffffffff, 0xffffffff);
        }
    }

    TEST_P(GLES2DecoderManualInitTest, CachedStencilMask)
    {
        InitState init;
        init.has_alpha = true;
        init.has_depth = true;
        init.has_stencil = true;
        init.request_alpha = true;
        init.request_depth = true;
        init.request_stencil = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        SetupDefaultProgram();
        SetupAllNeededVertexBuffers();
        SetupTexture();

        // Test all stencil_mask combinations twice.
        for (int i = 0; i < 4; i++) {
            GLuint stencil_mask = (i & 1) ? 0xf0f0f0f0 : 0x0f0f0f0f;

            // Toggle color masks to force ApplyDirtyState each time.
            DirtyStateMaskTest(0x1010, true, stencil_mask, 0xffffffff);
            DirtyStateMaskTest(0x0101, true, stencil_mask, 0xffffffff);
            DirtyStateMaskTest(0x1010, true, stencil_mask, 0xffffffff);
        }

        for (int i = 0; i < 4; i++) {
            GLuint stencil_mask = (i & 1) ? 0xf0f0f0f0 : 0x0f0f0f0f;

            // Toggle color masks to force ApplyDirtyState each time.
            DirtyStateMaskTest(0x1010, true, 0xffffffff, stencil_mask);
            DirtyStateMaskTest(0x0101, true, 0xffffffff, stencil_mask);
            DirtyStateMaskTest(0x1010, true, 0xffffffff, stencil_mask);
        }
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysNoAttributesSucceeds)
    {
        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDefaultDirtyState();

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Tests when the math overflows (0x40000000 * sizeof GLfloat)
    TEST_P(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0OverflowFails)
    {
        const GLsizei kLargeCount = 0x40000000;
        SetupTexture();
        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0).RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kLargeCount);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
        EXPECT_FALSE(GetDecoder()->WasContextLost());
    }

    // Tests when the math overflows (0x7FFFFFFF + 1 = 0x8000000 verts)
    TEST_P(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0PosToNegFails)
    {
        const GLsizei kLargeCount = 0x7FFFFFFF;
        SetupTexture();
        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0).RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kLargeCount);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
        EXPECT_FALSE(GetDecoder()->WasContextLost());
    }

    // Tests when the driver returns an error
    TEST_P(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0OOMFails)
    {
        const GLsizei kFakeLargeCount = 0x1234;
        SetupTexture();
        AddExpectationsForSimulatedAttrib0WithError(
            kFakeLargeCount, 0, GL_OUT_OF_MEMORY);
        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0).RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kFakeLargeCount);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
        EXPECT_FALSE(GetDecoder()->WasContextLost());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysBadTextureUsesBlack)
    {
        DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
        // This is an NPOT texture. As the default filtering requires mips
        // this should trigger replacing with black textures before rendering.
        DoTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGBA,
            3,
            1,
            0,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            kSharedMemoryId,
            kSharedMemoryOffset);
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        {
            InSequence sequence;
            EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
                .Times(1)
                .RetiresOnSaturation();
            EXPECT_CALL(
                *gl_, BindTexture(GL_TEXTURE_2D, TestHelper::kServiceBlackTexture2dId))
                .Times(1)
                .RetiresOnSaturation();
            EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
                .Times(1)
                .RetiresOnSaturation();
            EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
                .Times(1)
                .RetiresOnSaturation();
            EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId))
                .Times(1)
                .RetiresOnSaturation();
            EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
                .Times(1)
                .RetiresOnSaturation();
        }
        SetupExpectationsForApplyingDefaultDirtyState();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysMissingAttributesFails)
    {
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0);
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest,
        DrawArraysMissingAttributesZeroCountSucceeds)
    {
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0);
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, 0);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysValidAttributesSucceeds)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
        SetupExpectationsForApplyingDefaultDirtyState();

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Same as DrawArraysValidAttributesSucceeds, but with workaround
    // |init_vertex_attributes|.
    TEST_P(GLES2DecoderManualInitTest, InitVertexAttributes)
    {
        base::CommandLine command_line(0, NULL);
        command_line.AppendSwitchASCII(
            switches::kGpuDriverBugWorkarounds,
            base::IntToString(gpu::INIT_VERTEX_ATTRIBUTES));
        InitState init;
        init.has_alpha = true;
        init.has_depth = true;
        init.request_alpha = true;
        init.request_depth = true;
        init.bind_generates_resource = true;
        InitDecoderWithCommandLine(init, &command_line);
        SetupDefaultProgram();
        SetupTexture();
        SetupVertexBuffer();
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
        SetupExpectationsForApplyingDefaultDirtyState();

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysDeletedBufferFails)
    {
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        DeleteVertexBuffer();

        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0);
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysDeletedProgramSucceeds)
    {
        SetupTexture();
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDefaultDirtyState();
        DoDeleteProgram(client_program_id_, kServiceProgramId);

        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(1).RetiresOnSaturation();
        EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId)).Times(1);
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysWithInvalidModeFails)
    {
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0);
        DrawArrays cmd;
        cmd.Init(GL_QUADS, 0, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
        cmd.Init(GL_POLYGON, 0, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysInvalidCountFails)
    {
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        // Try start > 0
        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0);
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 1, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Try with count > size
        cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Try with attrib offset > 0
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 4);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Try with size > 2 (ie, vec3 instead of vec2)
        DoVertexAttribPointer(1, 3, GL_FLOAT, 0, 0);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Try with stride > 8 (vec2 + vec2 byte)
        DoVertexAttribPointer(1, 2, GL_FLOAT, sizeof(GLfloat) * 3, 0);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysInstancedANGLEFails)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, VertexAttribDivisorANGLEFails)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(_, _))
            .Times(0)
            .RetiresOnSaturation();

        VertexAttribDivisorANGLE cmd;
        cmd.Init(0, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLENoAttributesFails)
    {
        SetupTexture();

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLESimulatedAttrib0)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
        SetupExpectationsForApplyingDefaultDirtyState();

        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 3))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1))
            .Times(1)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, 3);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLEMissingAttributesFails)
    {
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)).Times(0);
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLEMissingAttributesZeroCountSucceeds)
    {
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)).Times(0);
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, 0, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLEValidAttributesSucceeds)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
        SetupExpectationsForApplyingDefaultDirtyState();

        EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0))
            .Times(1)
            .RetiresOnSaturation();

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 1))
            .Times(1)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLEWithInvalidModeFails)
    {
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)).Times(0);
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_QUADS, 0, 1, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
        cmd.Init(GL_POLYGON, 0, 1, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLEInvalidPrimcountFails)
    {
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _)).Times(0);
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, 1, -1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
    }

    // Per-instance data is twice as large, but number of instances is half
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLELargeInstanceSucceeds)
    {
        SetupTexture();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(
            *gl_,
            DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, kNumVertices / 2))
            .Times(1)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices / 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Regular drawArrays takes the divisor into account
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysWithDivisorSucceeds)
    {
        SetupTexture();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        // Access the data right at the end of the buffer.
        DoVertexAttribPointer(
            0, 2, GL_FLOAT, 0, (kNumVertices - 1) * 2 * sizeof(GLfloat));
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(
            *gl_,
            DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Per-instance data is twice as large, but divisor is twice
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLELargeDivisorSucceeds)
    {
        SetupTexture();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 2);
        EXPECT_CALL(
            *gl_,
            DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest, DrawArraysInstancedANGLELargeFails)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices + 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Per-index data is twice as large, but number of indices is half
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLELargeIndexSucceeds)
    {
        SetupTexture();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(
            *gl_,
            DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices / 2, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices / 2, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysInstancedANGLENoDivisor0Fails)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        DoVertexAttribDivisorANGLE(1, 1);
        EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawArraysInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawArraysNoDivisor0Fails)
    {
        SetupTexture();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        DoVertexAttribDivisorANGLE(1, 1);
        EXPECT_CALL(*gl_, DrawArrays(_, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsNoAttributesSucceeds)
    {
        SetupTexture();
        SetupIndexBuffer();
        AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
        SetupExpectationsForApplyingDefaultDirtyState();
        EXPECT_CALL(*gl_,
            DrawElements(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2)))
            .Times(1)
            .RetiresOnSaturation();
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsMissingAttributesFails)
    {
        SetupIndexBuffer();
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest,
        DrawElementsMissingAttributesZeroCountSucceeds)
    {
        SetupIndexBuffer();
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsExtraAttributesFails)
    {
        SetupIndexBuffer();
        DoEnableVertexAttribArray(6);

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsValidAttributesSucceeds)
    {
        SetupTexture();
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId);
        SetupExpectationsForApplyingDefaultDirtyState();

        EXPECT_CALL(*gl_,
            DrawElements(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2)))
            .Times(1)
            .RetiresOnSaturation();
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsDeletedBufferFails)
    {
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        DeleteIndexBuffer();

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceeds)
    {
        SetupTexture();
        SetupIndexBuffer();
        AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
        SetupExpectationsForApplyingDefaultDirtyState();
        DoDeleteProgram(client_program_id_, kServiceProgramId);

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
        EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId)).Times(1);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsWithInvalidModeFails)
    {
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_QUADS,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
        cmd.Init(GL_POLYGON,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsInvalidCountFails)
    {
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        // Try start > 0
        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES, kNumIndices, GL_UNSIGNED_SHORT, 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // Try with count > size
        cmd.Init(GL_TRIANGLES, kNumIndices + 1, GL_UNSIGNED_SHORT, 0);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsOutOfRangeIndicesFails)
    {
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kInvalidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kInvalidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsOddOffsetForUint16Fails)
    {
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsInstancedANGLEFails)
    {
        SetupTexture();
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLENoAttributesFails)
    {
        SetupTexture();
        SetupIndexBuffer();

        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLESimulatedAttrib0)
    {
        SetupTexture();
        SetupVertexBuffer();
        SetupIndexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId);
        SetupExpectationsForApplyingDefaultDirtyState();

        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(
            *gl_,
            DrawElementsInstancedANGLE(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2),
                3))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1))
            .Times(1)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            3);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLEMissingAttributesFails)
    {
        SetupIndexBuffer();
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)).Times(0);
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLEMissingAttributesZeroCountSucceeds)
    {
        SetupIndexBuffer();
        DoEnableVertexAttribArray(1);

        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)).Times(0);
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT, kValidIndexRangeStart * 2, 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLEValidAttributesSucceeds)
    {
        SetupIndexBuffer();
        SetupTexture();
        SetupVertexBuffer();
        DoEnableVertexAttribArray(1);
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
        AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId);
        SetupExpectationsForApplyingDefaultDirtyState();

        EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0))
            .Times(1)
            .RetiresOnSaturation();

        EXPECT_CALL(
            *gl_,
            DrawElementsInstancedANGLE(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2),
                1))
            .Times(1)
            .RetiresOnSaturation();

        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLEWithInvalidModeFails)
    {
        SetupIndexBuffer();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _)).Times(0);
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_QUADS,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
        cmd.Init(GL_INVALID_ENUM,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
    }

    // Per-instance data is twice as large, but number of instances is half
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLELargeInstanceSucceeds)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        // Add offset so we're sure we're accessing data near the end of the buffer.
        DoVertexAttribPointer(
            1,
            2,
            GL_FLOAT,
            0,
            (kNumVertices - kMaxValidIndex - 1) * 2 * sizeof(GLfloat));

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(
            *gl_,
            DrawElementsInstancedANGLE(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2),
                kNumVertices / 2))
            .Times(1)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            kNumVertices / 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Regular drawElements takes the divisor into account
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsWithDivisorSucceeds)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        // Add offset so we're sure we're accessing data near the end of the buffer.
        DoVertexAttribPointer(
            1,
            2,
            GL_FLOAT,
            0,
            (kNumVertices - kMaxValidIndex - 1) * 2 * sizeof(GLfloat));

        DoEnableVertexAttribArray(0);
        // Access the data right at the end of the buffer.
        DoVertexAttribPointer(
            0, 2, GL_FLOAT, 0, (kNumVertices - 1) * 2 * sizeof(GLfloat));
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(
            *gl_,
            DrawElements(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2)))
            .Times(1)
            .RetiresOnSaturation();
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Per-instance data is twice as large, but divisor is twice
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLELargeDivisorSucceeds)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 2);
        EXPECT_CALL(
            *gl_,
            DrawElementsInstancedANGLE(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2),
                kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLELargeFails)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            kNumVertices + 1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        cmd.Init(GL_TRIANGLES,
            kInvalidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kInvalidIndexRangeStart * 2,
            kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLEInvalidPrimcountFails)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            -1);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    // Per-index data is twice as large, but values of indices are smaller
    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLELargeIndexSucceeds)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        SetupExpectationsForApplyingDefaultDirtyState();
        DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        EXPECT_CALL(
            *gl_,
            DrawElementsInstancedANGLE(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2),
                kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsInstancedANGLENoDivisor0Fails)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        DoVertexAttribDivisorANGLE(1, 1);
        EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawElementsInstancedANGLE cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2,
            kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderGeometryInstancingTest,
        DrawElementsNoDivisor0Fails)
    {
        SetupTexture();
        SetupIndexBuffer();
        SetupVertexBuffer();
        DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);

        DoEnableVertexAttribArray(0);
        DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
        DoVertexAttribDivisorANGLE(0, 1);
        DoVertexAttribDivisorANGLE(1, 1);
        EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
            .Times(0)
            .RetiresOnSaturation();
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawArraysClearsAfterTexImage2DNULL)
    {
        SetupAllNeededVertexBuffers();
        DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
        // Create an uncleared texture with 2 levels.
        DoTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
        DoTexImage2D(
            GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
        // Expect 2 levels will be cleared.
        SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
            GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
            GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
        SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
            GL_TEXTURE_2D, GL_TEXTURE_2D, 1, GL_RGBA,
            GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 1, 1);
        SetupExpectationsForApplyingDefaultDirtyState();
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // But not again
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawElementsClearsAfterTexImage2DNULL)
    {
        SetupAllNeededVertexBuffers();
        SetupIndexBuffer();
        DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
        // Create an uncleared texture with 2 levels.
        DoTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
        DoTexImage2D(
            GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
        // Expect 2 levels will be cleared.
        SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
            GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
            GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
        SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
            GL_TEXTURE_2D, GL_TEXTURE_2D, 1, GL_RGBA,
            GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 1, 1);
        SetupExpectationsForApplyingDefaultDirtyState();

        EXPECT_CALL(*gl_,
            DrawElements(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2)))
            .Times(1)
            .RetiresOnSaturation();
        DrawElements cmd;
        cmd.Init(GL_TRIANGLES,
            kValidIndexRangeCount,
            GL_UNSIGNED_SHORT,
            kValidIndexRangeStart * 2);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // But not again
        EXPECT_CALL(*gl_,
            DrawElements(GL_TRIANGLES,
                kValidIndexRangeCount,
                GL_UNSIGNED_SHORT,
                BufferOffset(kValidIndexRangeStart * 2)))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawClearsAfterTexImage2DNULLInFBO)
    {
        const GLuint kFBOClientTextureId = 4100;
        const GLuint kFBOServiceTextureId = 4101;

        SetupAllNeededVertexBuffers();
        // Register a texture id.
        EXPECT_CALL(*gl_, GenTextures(_, _))
            .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
            .RetiresOnSaturation();
        GenHelper<GenTexturesImmediate>(kFBOClientTextureId);

        // Setup "render to" texture.
        DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
        DoTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
        DoBindFramebuffer(
            GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
        DoFramebufferTexture2D(GL_FRAMEBUFFER,
            GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D,
            kFBOClientTextureId,
            kFBOServiceTextureId,
            0,
            GL_NO_ERROR);
        DoEnableDisable(GL_SCISSOR_TEST, false);
        DoScissor(0, 0, 1, 1);

        // Setup "render from" texture.
        SetupTexture();

        SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER, // target
            GL_COLOR_BUFFER_BIT, // clear bits
            0, 0, 0,
            0, // color
            0, // stencil
            1.0f, // depth
            false, // scissor test
            0, 0, 1, 1);

        SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1111, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // But not again.
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawWitFBOThatCantClearDoesNotDraw)
    {
        const GLuint kFBOClientTextureId = 4100;
        const GLuint kFBOServiceTextureId = 4101;

        // Register a texture id.
        EXPECT_CALL(*gl_, GenTextures(_, _))
            .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
            .RetiresOnSaturation();
        GenHelper<GenTexturesImmediate>(kFBOClientTextureId);

        // Setup "render to" texture.
        DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
        DoTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
        DoBindFramebuffer(
            GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
        DoFramebufferTexture2D(GL_FRAMEBUFFER,
            GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D,
            kFBOClientTextureId,
            kFBOServiceTextureId,
            0,
            GL_NO_ERROR);

        // Setup "render from" texture.
        SetupTexture();

        EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
            .WillOnce(Return(GL_FRAMEBUFFER_UNSUPPORTED))
            .RetiresOnSaturation();
        EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0).RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest, DrawClearsAfterRenderbufferStorageInFBO)
    {
        SetupTexture();
        DoBindRenderbuffer(
            GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId);
        DoBindFramebuffer(
            GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
        DoRenderbufferStorage(
            GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 100, 50, GL_NO_ERROR);
        DoFramebufferRenderbuffer(GL_FRAMEBUFFER,
            GL_COLOR_ATTACHMENT0,
            GL_RENDERBUFFER,
            client_renderbuffer_id_,
            kServiceRenderbufferId,
            GL_NO_ERROR);
        DoEnableDisable(GL_SCISSOR_TEST, false);
        DoScissor(0, 0, 1, 1);

        SetupExpectationsForFramebufferClearing(GL_FRAMEBUFFER, // target
            GL_COLOR_BUFFER_BIT, // clear bits
            0, 0, 0,
            0, // color
            0, // stencil
            1.0f, // depth
            false, // scissor test
            0, 0, 1, 1);

        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1111, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderManualInitTest, DrawArraysClearsAfterTexImage2DNULLCubemap)
    {
        InitState init;
        init.gl_version = "opengl es 2.0";
        init.has_alpha = true;
        init.has_depth = true;
        init.request_alpha = true;
        init.request_depth = true;
        InitDecoder(init);

        static const GLenum faces[] = {
            GL_TEXTURE_CUBE_MAP_POSITIVE_X,
            GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
            GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
            GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
            GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
            GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
        };
        SetupCubemapProgram();
        DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId);
        // Fill out all the faces for 2 levels, leave 2 uncleared.
        for (int ii = 0; ii < 6; ++ii) {
            GLenum face = faces[ii];
            int32 shm_id = (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryId;
            uint32 shm_offset = (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryOffset;
            DoTexImage2D(face,
                0,
                GL_RGBA,
                2,
                2,
                0,
                GL_RGBA,
                GL_UNSIGNED_BYTE,
                shm_id,
                shm_offset);
            DoTexImage2D(face,
                1,
                GL_RGBA,
                1,
                1,
                0,
                GL_RGBA,
                GL_UNSIGNED_BYTE,
                shm_id,
                shm_offset);
        }
        // Expect 2 levels will be cleared.
        SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
            GL_TEXTURE_CUBE_MAP,
            GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA,
            GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
        SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
            GL_TEXTURE_CUBE_MAP,
            GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 1, GL_RGBA,
            GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 1, 1);
        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDefaultDirtyState();
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
    }

    TEST_P(GLES2DecoderWithShaderTest,
        DrawClearsAfterRenderbuffersWithMultipleAttachments)
    {
        const GLuint kFBOClientTextureId = 4100;
        const GLuint kFBOServiceTextureId = 4101;

        // Register a texture id.
        EXPECT_CALL(*gl_, GenTextures(_, _))
            .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
            .RetiresOnSaturation();
        GenHelper<GenTexturesImmediate>(kFBOClientTextureId);

        // Setup "render to" texture.
        DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
        DoTexImage2D(
            GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
        DoBindFramebuffer(
            GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
        DoFramebufferTexture2D(GL_FRAMEBUFFER,
            GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D,
            kFBOClientTextureId,
            kFBOServiceTextureId,
            0,
            GL_NO_ERROR);

        DoBindRenderbuffer(
            GL_RENDERBUFFER, client_renderbuffer_id_, kServiceRenderbufferId);
        DoBindFramebuffer(
            GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
        DoRenderbufferStorage(GL_RENDERBUFFER,
            GL_DEPTH_COMPONENT16,
            GL_DEPTH_COMPONENT,
            1,
            1,
            GL_NO_ERROR);
        DoFramebufferRenderbuffer(GL_FRAMEBUFFER,
            GL_DEPTH_ATTACHMENT,
            GL_RENDERBUFFER,
            client_renderbuffer_id_,
            kServiceRenderbufferId,
            GL_NO_ERROR);
        DoEnableDisable(GL_SCISSOR_TEST, false);
        DoScissor(0, 0, 1, 1);
        SetupTexture();
        SetupExpectationsForFramebufferClearing(
            GL_FRAMEBUFFER, // target
            GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, // clear bits
            0, 0, 0,
            0, // color
            0, // stencil
            1.0f, // depth
            false, // scissor test
            0, 0, 1, 1);

        AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
        SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB
            true, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1111, // color bits
            true, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderWithShaderTest,
        DrawingWithFBOTwiceChecksForFBOCompleteOnce)
    {
        const GLuint kFBOClientTextureId = 4100;
        const GLuint kFBOServiceTextureId = 4101;

        SetupAllNeededVertexBuffers();

        // Register a texture id.
        EXPECT_CALL(*gl_, GenTextures(_, _))
            .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
            .RetiresOnSaturation();
        GenHelper<GenTexturesImmediate>(kFBOClientTextureId);

        // Setup "render to" texture that is cleared.
        DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
        DoTexImage2D(GL_TEXTURE_2D,
            0,
            GL_RGBA,
            1,
            1,
            0,
            GL_RGBA,
            GL_UNSIGNED_BYTE,
            kSharedMemoryId,
            kSharedMemoryOffset);
        DoBindFramebuffer(
            GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
        DoFramebufferTexture2D(GL_FRAMEBUFFER,
            GL_COLOR_ATTACHMENT0,
            GL_TEXTURE_2D,
            kFBOClientTextureId,
            kFBOServiceTextureId,
            0,
            GL_NO_ERROR);

        // Setup "render from" texture.
        SetupTexture();

        // Make sure we check for framebuffer complete.
        EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
            .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
            .RetiresOnSaturation();

        SetupExpectationsForApplyingDirtyState(false, // Framebuffer is RGB
            false, // Framebuffer has depth
            false, // Framebuffer has stencil
            0x1111, // color bits
            false, // depth mask
            false, // depth enabled
            0, // front stencil mask
            0, // back stencil mask
            false); // stencil enabled

        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());

        // But not again.
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

    TEST_P(GLES2DecoderManualInitTest, DrawClearsDepthTexture)
    {
        InitState init;
        init.extensions = "GL_ANGLE_depth_texture";
        init.gl_version = "opengl es 2.0";
        init.has_alpha = true;
        init.has_depth = true;
        init.request_alpha = true;
        init.request_depth = true;
        init.bind_generates_resource = true;
        InitDecoder(init);

        SetupDefaultProgram();
        SetupAllNeededVertexBuffers();
        const GLenum attachment = GL_DEPTH_ATTACHMENT;
        const GLenum target = GL_TEXTURE_2D;
        const GLint level = 0;
        DoBindTexture(target, client_texture_id_, kServiceTextureId);

        // Create a depth texture.
        DoTexImage2D(target,
            level,
            GL_DEPTH_COMPONENT,
            1,
            1,
            0,
            GL_DEPTH_COMPONENT,
            GL_UNSIGNED_INT,
            0,
            0);

        // Set scissor rect and disable GL_SCISSOR_TEST to make sure we enable it in
        // the clear, then disable it and restore the rect again.
        DoScissor(0, 0, 32, 32);
        DoEnableDisable(GL_SCISSOR_TEST, false);

        EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
        EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _))
            .Times(1)
            .RetiresOnSaturation();

        EXPECT_CALL(*gl_,
            FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT,
                attachment,
                target,
                kServiceTextureId,
                level))
            .Times(1)
            .RetiresOnSaturation();
        EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT))
            .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
            .RetiresOnSaturation();

        EXPECT_CALL(*gl_, ClearStencil(0)).Times(1).RetiresOnSaturation();
        SetupExpectationsForStencilMask(GLES2Decoder::kDefaultStencilMask,
            GLES2Decoder::kDefaultStencilMask);
        EXPECT_CALL(*gl_, ClearDepth(1.0f)).Times(1).RetiresOnSaturation();
        SetupExpectationsForDepthMask(true);
        SetupExpectationsForEnableDisable(GL_SCISSOR_TEST, true);
        EXPECT_CALL(*gl_, Scissor(0, 0, 1, 1)).Times(1).RetiresOnSaturation();

        EXPECT_CALL(*gl_, Clear(GL_DEPTH_BUFFER_BIT)).Times(1).RetiresOnSaturation();

        SetupExpectationsForRestoreClearState(0.0f, 0.0f, 0.0f, 0.0f, 0, 1.0f, false,
            0, 0, 32, 32);

        EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
        EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0))
            .Times(1)
            .RetiresOnSaturation();

        SetupExpectationsForApplyingDefaultDirtyState();
        EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
            .Times(1)
            .RetiresOnSaturation();
        DrawArrays cmd;
        cmd.Init(GL_TRIANGLES, 0, kNumVertices);
        EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
        EXPECT_EQ(GL_NO_ERROR, GetGLError());
    }

} // namespace gles2
} // namespace gpu
